package com.hrt.common.web;

import com.btcode.orm.conver.DefaultValueConver;
import com.btcode.orm.conver.IValueConver;
import com.btcode.orm.model.IField;
import com.btcode.orm.model.IModel;
import com.btcode.orm.relation.ex.IRelation;
import com.btcode.web.core.unit.WebContext;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

/**
 * @author Joey Huang QQ:273179370
 * @create 2018-07-11
 */
@SuppressWarnings("rawtypes")
public class JsonRequestUnit extends com.btcode.web.core.unit.RequestUnit {

    private static Gson gson = new Gson();
    private static IValueConver valueConvert = new DefaultValueConver();

    public static String getString(String parameterName) {
        try {
            WebContext.getRequest().setCharacterEncoding("utf-8");
            return WebContext.getRequest().getParameter(parameterName);
        }
        catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static Integer getInt(String paramName) {
        try {
            String str = getString(paramName);
            if (str != null) {
                return Integer.parseInt(str.trim());
            }
            else {
                return null;
            }
        }
        catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static Double getDouble(String paramName) {
        try {
            String str = getString(paramName);
            if (str != null) {
                return Double.parseDouble(str.trim());
            }
            else {
                return null;
            }
        }
        catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static <T extends IModel> T getModel(Class<T> modelClass, String jsonStr) {
        try {
            HashMap<?, ?> map = gson.fromJson(jsonStr, HashMap.class);
            return convertToModel(modelClass, map);
        }
        catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static <T extends IModel> T getPureModel(Class<T> modelClass, String jsonStr) {
        try {
            HashMap<?, ?> map = gson.fromJson(jsonStr, HashMap.class);
            return convertToPureModel(modelClass, map);
        }
        catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static <T extends IModel> List<T> getModels(Class<T> modelClass, String jsonStr) {
        try {
            List<T> modelList = new ArrayList<>();
            TypeToken<List<HashMap>> typeToken = new TypeToken<List<HashMap>>() {
            };
            List<HashMap> list = gson.fromJson(jsonStr, typeToken.getType());
            if (!CollectionUtils.isEmpty(list)) {
                for (HashMap map : list) {
                    T model = convertToModel(modelClass, map);
                    modelList.add(model);
                }
            }
            return modelList;
        }
        catch (Exception e) {
            e.printStackTrace();
            return Collections.emptyList();
        }
    }

    public static <T extends IModel> List<T> getPureModels(Class<T> modelClass, String jsonStr) {
        try {
            List<T> modelList = new ArrayList<>();
            TypeToken<List<HashMap>> typeToken = new TypeToken<List<HashMap>>() {
            };
            List<HashMap> list = gson.fromJson(jsonStr, typeToken.getType());
            if (!CollectionUtils.isEmpty(list)) {
                for (HashMap map : list) {
                    T model = convertToPureModel(modelClass, map);
                    modelList.add(model);
                }
            }
            return modelList;
        }
        catch (Exception e) {
            e.printStackTrace();
            return Collections.emptyList();
        }
    }

    private static <T extends IModel> T convertToModel(Class<T> targetClass, Map map) throws Exception {
        Assert.notNull(targetClass, "model class is null");
        T model = targetClass.newInstance();
        List<IField> fields = model.getFields();
        for (IField field : fields) {
            Object value = map.get(field.getFieldName());
            value = valueConvert.conveToORMValue(field, value);
            model.setFieldValue(field.getFieldName(), value);
        }
        Map relationModelMap = (Map) map.get("relationModelMap");
        List<IRelation> relationList = model.getRelations();
        if (!CollectionUtils.isEmpty(relationModelMap) && !CollectionUtils.isEmpty(relationList)) {
            for (IRelation relation : relationList) {
                Class<IModel> modelClass = relation.getSlaveField().getModelClass();
                String tableName = relation.getSlaveField().getModelClass().newInstance()
                    .getTableName();
                @SuppressWarnings("unchecked") List<Map> relationTableList = (List<Map>) relationModelMap
                    .get(tableName);
                if (!CollectionUtils.isEmpty(relationTableList)) {
                    List<IModel> slaveModelList = new ArrayList<>();
                    for (Map slaveMap : relationTableList) {
                        IModel slaveModel = convertToModel(modelClass, slaveMap);
                        slaveModelList.add(slaveModel);
                    }
                    model.setRelationModel(tableName, slaveModelList);
                }
            }
        }
        return model;
    }

    private static <T extends IModel> T convertToPureModel(Class<T> modelClass, Map map) throws Exception {
        Assert.notNull(modelClass, "model class is null");
        T model = modelClass.newInstance();
        List<IField> fields = model.getFields();
        for (IField field : fields) {
            Object value = map.get(field.getFieldName());
            value = valueConvert.conveToORMValue(field, value);
            model.setFieldValue(field.getFieldName(), value);
        }
        return model;
    }
}
